package pso.velocity;

import pso.mcpso.MCPSOAlgorithm;
import pso.particle.Particle;

public class MCPSOVelocityUpdateStrategy extends
		ConstantInertiaWeightVelocityUpdateStrategy {

	private MCPSOAlgorithm algorithm;
	private double slaveFactor = 2;

	public MCPSOVelocityUpdateStrategy(double inertiaWeight,
			MCPSOAlgorithm algorithm) {
		super(inertiaWeight);
		this.algorithm = algorithm;
	}

	@Override
	public void updateVelocities(Particle[] particles) {
		if (particles[0].getNeighborhood().getBestValue() > algorithm
				.getBestSlaveValue()) {
			super.updateVelocities(particles);
		} else {
			double[] bestSlavePosition = algorithm.getBestSlavePosition();
			for (Particle particle : particles) {
				updateVelocityAccordingToSlave(particle, bestSlavePosition,
						inertiaWeight);
			}
		}
	}

	public void updateVelocityAccordingToSlave(Particle particle,
			double[] bestSlavePosition, double inertiaWeight) {
		double[] position = particle.getPosition();
		int dimensions = position.length;
		double[] bestParticlePosition = particle.getBestPosition();

		double[] newVelocity = new double[dimensions];
		for (int i = 0; i < dimensions; i++) {
			double cognitivePart = cognitiveFactor
					* randomGenerator.nextDouble()
					* (bestParticlePosition[i] - position[i]);

			double slavePart = slaveFactor * randomGenerator.nextDouble()
					* (bestSlavePosition[i] - position[i]);

			newVelocity[i] = calculateNewVelocity(particle.getVelocity()[i],
					cognitivePart, slavePart);
		}
		particle.setVelocity(newVelocity);
	}

	public double getSlaveFactor() {
		return slaveFactor;
	}

	public void setSlaveFactor(double slaveFactor) {
		this.slaveFactor = slaveFactor;
	}

	public MCPSOAlgorithm getAlgorithm() {
		return algorithm;
	}

	public void setAlgorithm(MCPSOAlgorithm algorithm) {
		this.algorithm = algorithm;
	}
}
